import threading
import time
import uuid

from Project.HTools.tcp.socket_panel import SocketClientPanel
import socket
import wx
import datetime


class SocketMain(SocketClientPanel):
    def __init__(self, parent):
        SocketClientPanel.__init__(self, parent)
        self.clientSocket = None
        self.serverSocket = None
        self.is_socket_connect = False
        self.isServerOpen = False
        self.clients = {}

        # 设置输入框的初始值
        self.edit_ip.SetValue('192.168.0.10')
        self.edit_port.SetValue('1024')
        self.edit_log.SetEditable(False)
        self.edit_log.SetCanFocus(False)
        self.edit_receive.SetEditable(False)

        self.setCanModify(True)
        #  0-客户端 1-服务端
        self.model = 0

    def open(self, event):
        if self.model == 0:
            self.openClient()
        elif self.model == 1:
            self.openServer()

    def openClient(self):
        if not self.is_socket_connect:
            if self.edit_ip.GetValue() == '' or self.edit_port.GetValue() == '':
                self.alertMessage('ip和端口号不能为空')
                return
            try:
                ip = self.edit_ip.GetValue()
                port = int(self.edit_port.GetValue())
                self.clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.clientSocket.connect((ip, port))
                self.is_socket_connect = True
                message_thread = threading.Thread(target=self.listenServerMessage)
                message_thread.start()
                self.writelog('连接成功')
                self.btn_open.SetLabel('关闭')
                self.setCanModify(False)
            except Exception as e:
                self.writelog(str(e))
                self.is_socket_connect = False
        else:  # 断开连接
            try:
                self.clientSocket.close()
                self.btn_open.SetLabel('打开')
                self.is_socket_connect = False
                self.writelog('断开连接')
                self.setCanModify(True)
            except Exception as e:
                self.writelog(str(e))

    def openServer(self):
        if not self.isServerOpen:
            if self.edit_port.GetValue() == '':
                self.alertMessage('端口号不能为空')
                return
            try:
                self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                port = int(self.edit_port.GetValue())
                self.serverSocket.bind((socket.gethostname(), port))
                self.serverSocket.listen(10)
                self.isServerOpen = True
                self.btn_open.SetLabel('关闭')
                self.setCanModify(False)
                self.writelog('TCP服务端启动成功 at port {}'.format(port))
                thread = threading.Thread(target=self.acceptClient)
                thread.start()

            except Exception as e:
                self.writelog(str(e))
                self.isServerOpen = False
                self.setCanModify(True)
        else:  # 关闭服务端
            try:
                self.serverSocket.close()
                self.btn_open.SetLabel('打开')
                self.isServerOpen = False
                self.writelog('关闭服务端')
                self.clients = {}
                self.setCanModify(True)
            except Exception as e:
                self.writelog(str(e))

    # 监听服务端发送过来的消息
    def listenServerMessage(self):
        while self.is_socket_connect:
            try:
                message = self.clientSocket.recv(1024)
                self.receiveMessage(message.decode())
            except Exception as e:
                self.writelog(str(e))
                break

    # 监听客户端发送过来的消息
    def listenClientMessage(self, client_id, socket):
        while self.isServerOpen:
            try:
                message = socket.recv(1024)
                self.receiveMessage(message.decode())
            except Exception as e:
                socket.close()
                if client_id in self.clients:
                    del self.clients[client_id]
                self.writelog(str(e))
                break

    def acceptClient(self):
        while self.isServerOpen:
            try:
                client_socket, addr = self.serverSocket.accept()
                client_id = str(uuid.uuid4())
                self.clients[client_id] = client_socket
                self.writelog('TCP socket NO {} {} is accepted!'.format(len(self.clients), addr))
                thread = threading.Thread(target=self.listenClientMessage, args=(client_id, client_socket))
                thread.start()
            except Exception as e:
                self.isServerOpen = False
                break

    def writelog(self, string):
        converted_time = datetime.datetime.fromtimestamp(time.time())
        result_date = converted_time.strftime('%Y-%m-%d %H:%M:%S')
        full_log = "{} {}\n".format(result_date, string)
        wx.CallAfter(self.edit_log.AppendText, full_log + '\n')

    def receiveMessage(self, msg):
        wx.CallAfter(self.edit_receive.AppendText, msg + '\n')

    def sendMessage(self, event):
        message = self.edit_send.GetValue()
        if message == '':
            self.alertMessage('发送的消息不能为空')
            return
        if self.model == 0:
            if not self.is_socket_connect:
                self.alertMessage('请先连接服务端')
                return
            self.clientSocket.send(message.encode('gb2312'))
        elif self.model == 1:
            if not self.isServerOpen:
                self.alertMessage('请先打开服务端')
                return
            for client in self.clients.values():
                client.send(message.encode('gb2312'))

    def alertMessage(self, message):
        wx.MessageDialog(self, message, '操作提醒', wx.OK).ShowModal()

    def clear_send_input(self, event):
        self.edit_send.SetValue('')

    def clear_receive_input(self, event):
        self.edit_receive.SetValue('')

    # 清除所有接收和发送的信息
    def clearAll(self):
        self.edit_receive.SetValue('')
        self.edit_send.SetValue('')

    # 选中客户端
    def choose_client(self, event):
        self.model = 0
        self.clearAll()
        if self.serverSocket is not None:
            self.serverSocket = None

    # 选中服务端
    def choose_server(self, event):
        self.model = 1
        self.clearAll()
        if self.clientSocket is not None:
            self.clientSocket = None

    # 设置输入框是否可编辑
    def setCanModify(self, can):
        if can:
            self.edit_ip.SetEditable(True)
            self.edit_port.SetEditable(True)
            self.clientRadioBtn.Enable(True)
            self.serverRadioBtn.Enable(True)
        else:
            self.edit_ip.SetEditable(False)
            self.edit_port.SetEditable(False)
            self.clientRadioBtn.Enable(False)
            self.serverRadioBtn.Enable(False)
